package coolapk.cj.cj.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import coolapk.cj.cj.entity.Goods;
import coolapk.cj.cj.entity.GroupMember;
import coolapk.cj.cj.entity.Person;
import coolapk.cj.cj.service.GoodsService;
import coolapk.cj.cj.service.GroupMemberService;
import coolapk.cj.cj.service.PersonService;
import coolapk.cj.cj.utils.CqhttpUtil;
import coolapk.cj.cj.utils.SpelExpressionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wenjunjun9
 * @created 2021-02-19 19:35
 * @description
 */
@Slf4j
@Component
public class LotteryJob {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private PersonService personService;

    @Autowired
    private GroupMemberService groupMemberService;

    @Scheduled(cron = "0 0 22 * * ?")
    public void lottery() {
        LocalDate currentDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        log.info("{}: 开始抽奖啦啦啦！", formatter.format(currentDate));

        // 获取今日抽奖奖品列表
        Wrapper<Goods> goodsWrapper = Wrappers.<Goods>lambdaQuery()
                .apply("date_format(publish_time,'%Y-%m-%d') = {0}", formatter.format(currentDate));
        List<Goods> goodsList = goodsService.list(goodsWrapper);
        List<Long> goodsIdList = goodsList.stream().map(Goods::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(goodsIdList)) {
            log.info("{}: 今天没有奖品！", formatter.format(currentDate));
            return;
        }

        Wrapper<Person> personWrapper = Wrappers.<Person>lambdaQuery()
                .in(Person::getGoodsId, goodsIdList);
        List<Person> personList = personService.list(personWrapper);
        if (CollUtil.isEmpty(personList)) {
            log.info("{}: 今日无人抽奖！", formatter.format(currentDate));
            return;
        }
        // 过滤掉近半年已经抽过的qq
        LambdaQueryWrapper<Goods> goodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        goodsLambdaQueryWrapper.gt(Goods::getWinnerTime, DateUtil.offsetMonth(new Date(), -6))
                .select(Goods::getWinner);
        List<Goods> winnerList = goodsService.list(goodsLambdaQueryWrapper);
        if (CollUtil.isNotEmpty(winnerList)) {
            personList = personList.stream().filter(item ->
                                winnerList.stream().map(Goods::getWinner).noneMatch(winner -> item.equals(item.getQq()))
                            ).collect(Collectors.toList());
        }
        Map<Long, List<Person>> personMap = personList.stream().collect(Collectors.groupingBy(Person::getGoodsId));

        List<Person> resultPersonList = new ArrayList<>();
        List<String> filterList = new ArrayList<>();
        personMap.forEach((item, list) -> {
            List<Person> newList = list.stream().filter(person -> !filterList.contains(person.getQq())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(newList)) {
                log.warn("{}: 抽奖人数不够，剩余奖品等待下次抽取", formatter.format(currentDate));
                return;
            }
            Person person = randomPerson(newList);
            log.info("{}: 中奖用户 -> {}", formatter.format(currentDate), person.getQq());
            filterList.add(person.getQq());
            resultPersonList.add(person);
        });

        for (int i = 0; i < goodsList.size(); i++) {
            Person person = resultPersonList.get(i);
            Goods goods = goodsList.get(i);
            goods.setWinner(person.getQq());
            goods.setWinnerTime(LocalDateTime.now());
        }
        goodsService.updateBatchById(goodsList);
    }

    /**
     *  更新群成员列表
     *  每小时更新一次
     */
    @Scheduled(cron = "0 0 */1 * * ?")
    public void updateGroupMember() {
        try {
            Map<String, Object> groupMemberMap = CqhttpUtil.getGroupMembers();
            if (CollectionUtils.isNotEmpty(groupMemberMap)) {
                List<GroupMember> groupMemberList = groupMemberMap.entrySet().parallelStream().map(Map.Entry::getValue).map(this::generateGroupMember).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(groupMemberList)) {
                    log.error("未解析到有效成员信息，群成员信息更新终止");
                    return;
                }
                List<String> qqList = groupMemberList.parallelStream().map(GroupMember::getQq).collect(Collectors.toList());

                LambdaQueryWrapper<GroupMember> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.in(GroupMember::getQq, qqList).select(GroupMember::getQq, GroupMember::getId);
                List<GroupMember> existsMemberList = groupMemberService.list(queryWrapper);

                if (CollectionUtils.isEmpty(existsMemberList)) {
                    groupMemberService.saveBatch(groupMemberList);
                    log.info("首次更新群成员 {} 条", groupMemberList.size());
                } else {
                    Map<String, Long> existsQQMap = existsMemberList.parallelStream().collect(Collectors.toMap(GroupMember::getQq, GroupMember::getId));
                    Map<Boolean, List<GroupMember>> groupByMap = groupMemberList.parallelStream().collect(Collectors.groupingBy(item -> existsQQMap.containsKey(item.getQq())));
                    List<GroupMember> updateMemberList = groupByMap.get(true);
                    List<GroupMember> insertMemberList = groupByMap.get(false);
                    if (CollectionUtils.isNotEmpty(updateMemberList)) {
                        updateMemberList.parallelStream().forEach(item -> {
                            item.setId(existsQQMap.get(item.getQq()));
                        });
                        groupMemberService.updateBatchById(updateMemberList);
                        log.info("本次更新成员信息 {} 条", updateMemberList.size());
                    }
                    if (CollectionUtils.isNotEmpty(insertMemberList)) {
                        groupMemberService.saveBatch(insertMemberList);
                        log.info("本次新增成员信息 {} 条", insertMemberList.size());
                    }
                }
            } else {
                log.error("群成员获取为空");
            }
        } catch (Exception e) {
            log.error("更新群成员出错", e);
        }
    }

    /**
     * 更新成员上次发言时间
     * 每天更新一次
     */
    @Scheduled(cron = "0 0 0 */1 * ?")
    public void updateMemberLastSendTime() {
        try {
            LambdaQueryWrapper<GroupMember> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(GroupMember::getQq, GroupMember::getId);
            List<GroupMember> groupMemberList = groupMemberService.list(queryWrapper);
            if (CollectionUtils.isEmpty(groupMemberList)) {
                log.error("群成员为空，上次发言时间更新终止");
            } else {
                for (GroupMember groupMember : groupMemberList) {
                    Thread.sleep(500);
                    JSONObject memberInfo = CqhttpUtil.getMemberInfoByQq(groupMember.getQq());
                    Integer lastSentTime = (Integer) memberInfo.get("last_sent_time");
                    groupMember.setLastSentTime(LocalDateTime.ofEpochSecond(lastSentTime, 0, ZoneOffset.ofHours(8)));
                }
                groupMemberService.updateBatchById(groupMemberList);
                log.info("更新上次发言成员 {} 条", groupMemberList.size());
            }
        } catch (Exception e) {
            log.error("更新群成员上次发言时间出错", e);
        }
    }

    /**
     * 从json数据中提取封装对象信息
     * @param obj
     * @return
     */
    private GroupMember generateGroupMember(Object obj) {
        GroupMember groupMember =  null;
        try {
            String qq = SpelExpressionUtils.getValue("#root.user_id", obj, String.class);
            String groupId = SpelExpressionUtils.getValue("#root.group_id", obj, String.class);
            String nickname = SpelExpressionUtils.getValue("#root.nickname", obj, String.class);
            String card = SpelExpressionUtils.getValue("#root.card", obj, String.class);
            Long joinTime = SpelExpressionUtils.getValue("#root.join_time", obj, Long.class);
//            Long lastSentTime = SpelExpressionUtils.getValue("#root.last_sent_time", obj, Long.class);
            String level = SpelExpressionUtils.getValue("#root.level", obj, String.class);
            String role = SpelExpressionUtils.getValue("#root.role", obj, String.class);
            String sex = SpelExpressionUtils.getValue("#root.sex", obj, String.class);
            groupMember = new GroupMember(null, qq, groupId, nickname, card, LocalDateTime.ofEpochSecond(joinTime, 0, ZoneOffset.ofHours(8)),
                    null, level, role, sex);
        } catch (Exception e) {
            log.error("处理json数据出错", e);
        }
        return groupMember;
    }

    private Person randomPerson(List<Person> personList) {
        int[] randoms = new int[10];
        for (int i = 0; i < 10; i++) {
            int random = (int) Math.floor(Math.random() * personList.size());
            randoms[i] = random;
        }
        int randomIndex = (int) Math.floor(Math.random() * 10);
        return personList.get(randoms[randomIndex]);
    }

}
